(*
* rewrite in caml
*)

open List
open Printf
open Randif ;;

let rotate ls = 
  match ls with 
  |  [] -> []
  |  h :: hs -> hs @ [h]

let miy = 12

let miyf = float_of_int miy

type date = 
    { year : int;
      month : int }

let zeroDate = { year = 0; month = 0 }

let printDate { year = y; month = m } 
    = sprintf "y-%d m-%d" y m

let date_of_float f = 
  let (frac,inte) = modf f in
  { year = (truncate inte) ;
    month = (truncate (frac *. miyf)) }

type cash = float

let incDate = function
    { year = i ; month = 11} -> {year = (i+1) ; month = 0 }
  | { year = y ; month = m } -> {year = y ; month = (m+1) }


let decDate = function
    { year = i ; month = 0} -> {year = (i-1) ; month = (miy - 1) }
  | { year = y ; month = m } -> {year = y ; month = (m-1) }


let sumDate d1 d2 = 
  let { year = y1 ; month = m1 } = d1 in
  let { year = y2 ; month = m2 } = d2 in
  if m1 + m2 < miy
  then { year = (y1 + y2); month = (m1 + m2) }
  else { year = (y1 + y2 + 1); month = (m1 + m2 - miy) }

let diffDate d1 d2 = (* d1 - d2 *)
  let { year = y1 ; month = m1 } = d1 in
  let { year = y2 ; month = m2 } = d2 in
  if m1 - m2 >= 0
  then { year = (y1 - y2); month = (m1 - m2) }
  else { year = (y1 - y2 - 1); month = (m1 - m2 + miy) }


let monthPart { month = m } = m

let yearPart { year = y } = y

let dateFloat { year = y; month = m} 
    = (float_of_int y) +. (float_of_int m) /. miyf

let timeToRecover = { year = 0; month = 5 } (* six months to recover bad debts *)

let id o = o

let pi = 3.14159

type bond = { start: date ;
              maturity: date ;
              rate: float ;
              principal: cash ;
              rdefault: float ; 
              recovery: float } 

let printBond { start= st ;
		maturity= mat ;
		rate= rt ;
		principal= prin ;
		rdefault = def ; 
		recovery = reco } =
  sprintf "Bond: %f at %f%%, start %s, end %s, defrate %f recovery %f"
    prin (rt *. 100.) (printDate st) (printDate mat) def reco

type defbond = { recdate : date ;
		 defprincipal : cash ;
		 recamount : cash }

type contract = 
  | Bond of bond
  | DefaultedBond of defbond
  | NullBond

let zeroBond = { start = zeroDate;
		 maturity = zeroDate;
		 rate = 0.0;
		 principal = 0.0;
		 rdefault= 0.0;
		 recovery = 0.0 }

let maturityBetween b dt m1 m2 =
  match b with
  | Bond {maturity = mat} -> (dateFloat dt) +. m1 <= (dateFloat mat) 
	                     && (dateFloat mat) >= (dateFloat dt) +. m2
  | _ -> 1 == 0

type party =
  | Lender  (* SOURCE OF WHOLESALE FUNDING  - LENDS TO BANK *)
  | Borrower  (* TAKER OF MONEY FROM BANK *)
(*  | Regulator  *)

let print_party p =
  match p with
  | Lender -> "Lender"
  | Borrower -> "Borrower"

type contractFactory 
    = { defaultDist:probabilityDistribution;
        principalDist:probabilityDistribution;
        rateStep:probabilityDistribution;
        rateStart:probabilityDistribution;
        durationDist:probabilityDistribution;
        recoveryDist:probabilityDistribution;
	maxOfferSteps:int;
        offeror:party }

let sum x = fold_left (+.) 0. x

let meanv x = (sum x) /. (float_of_int (length x))

let rec replicate n t =
  if n == 0
  then []
  else t :: (replicate (n-1) t) 


let (--) i j = 
  let rec aux n acc =
    if n < i then acc else aux (n-1) (n :: acc)
  in aux j [] ;;

(*      val ( -- ) : int -> int -> int list = <fun> *)
